---
title: Determine whether the current user may view a policy
summary: Authorizes or denies the current user's access to a specific policy based on user type, secure-policy code, and per-user-type ownership/assignment checks.
status: draft
owner: SAIF Claims BOF team
last_reviewed: 2026-08-21
library: SAIF.Business.View.Policy
reference_type: embedded
operation_id: OP-VP-002
trigger: Caller invokes clsPolicySecurity.IsPolicyValidForUser(...)
---

# Determine whether the current user may view a policy

The core authorization entry point of this library: determines whether the current
`clsSecurityPrincipal`/`clsUserType` may view a given policy, branching by user type and applying
per-type ownership, assignment, or group-membership checks.

| Field | Value |
| --- | --- |
| **Operation ID** | OP-VP-002 |
| **Trigger** | Caller invokes `clsPolicySecurity.IsPolicyValidForUser(inPolicyData)` (or the `Decimal` policy-number overload) |
| **Inputs** | `clsPolicyData` (or a policy number, resolved internally via [Retrieve policy header data](retrieve-policy-header-data.md)), current `clsSecurityPrincipal`/`clsUserType` |
| **Outputs** | `Boolean hasAccess` |
| **Primary components** | `clsPolicySecurity.IsPolicyValidForUser`, `clsPolicySecurity.IsPolicyValidForParentPolicy` |
| **Entry point** | `SAIF.Business.View.Policy\clsPolicySecurity.vb` |

## Steps

1. Caller constructs `clsPolicySecurity(SecurityPrincipal, DPI)`; the constructor immediately
   builds a `clsUserType` from the principal and initializes a secondary SQL Server
   `IDataPortalInfo` via `clsSQLDataLayer` (reads config settings `BDS_USER`, `bdsDatabase`,
   `BDS_DATABASENAME` — see [Configuration settings](../configuration.md)).
2. Caller calls `IsPolicyValidForUser(inPolicyData)` (or the `Decimal` policy-number overload,
   which first calls [Retrieve policy header data](retrieve-policy-header-data.md) and then
   delegates to the object overload).
3. Enforces [BR-VP-002](../business-rules.md#br-vp-002-secure-policy-ad-resource-gate):
   if the policy's `SecurePolicyCode = clsConstants.SAIF` and the principal is **not** authorized
   for AD resource `SAIFpolicyInfo`, access is denied outright regardless of user type.
   - On failure: return `False` immediately; no further branching by user type occurs.
4. Enforces [BR-VP-003](../business-rules.md#br-vp-003-policy-validity-and-non-zero-policy-number-required-for-access):
   if `inPolicyData.IsValid = False` or `PolicyNum = 0`, access is denied.
   - On failure: return `False` immediately.
5. Branches by `UserType.UserType`:
   - `SaifEmployee`, `MCO`, `MedProv`, `Bookkeeper` → always granted
     ([BR-VP-004](../business-rules.md#br-vp-004-unconditional-access-for-internal-staff-user-types)).
   - `Agent` → granted if the user's number matches `inPolicyData.AgentNum` or
     `inPolicyData.Agency.AgencySeqNum`
     ([BR-VP-005](../business-rules.md#br-vp-005-agent-ownership-match-required)).
   - `PolicyHolder` → delegates to `IsPolicyValidForParentPolicy`
     ([BR-VP-006](../business-rules.md#br-vp-006-policyholder-ownership-affiliation-match-required)),
     which checks the association "Parents" list on the requesting user's own `clsPolicyData`
     (`UsersPolicyData`) for a matching policy number, or a direct number match.
     - `UsersPolicyData.Associations` is populated via
       `Associations\clsPolicyAssociationFactory.GetPolicyHeaderAssociations`, which calls into
       `SAIF.Business.Policy`'s `IPolicyAssociationType`/category grouping logic.

       > **Origin**: This delegation is to `SAIF.Business.Policy` (an internal project reference,
       > not `frameworkDensity`-tracked); the step sequence within that library was not traced
       > further — out of scope for this library's analysis.
   - `Group` → calls `IsInGroup`
     ([BR-VP-007](../business-rules.md#br-vp-007-group-membership-required)), a SQL Server
     stored-procedure scalar query ([SQL-VP-033](../sql/SQL-033-isingroup.md), aliased in code as
     `"IsInGroup"`).
   - `LossControl` → looks up the assigned Loss Control Consultant team member for the policy
     (`clsTeamAssignmentCollection.Item(TeamFunctions.LossControlConsultant)`) and compares the
     (masked or unmasked) username prefix against the user's own number via
     `CanSafetyConsultantAccessPolicy`
     ([BR-VP-008](../business-rules.md#br-vp-008-loss-control-consultant-assignment-match-required)).
     - If no team assignment exists: access is denied.
   - `Auditor` → calls `CanAuditorAccessPolicy`
     ([BR-VP-009](../business-rules.md#br-vp-009-fee-auditor-vendor-policy-audit-record-match-required)),
     an inline Oracle SQL query ([SQL-VP-037](../sql/SQL-037-canauditoraccesspolicy.md)) joining
     `PA_AUDIT`, `PA_AUDITOR`, and `PA_POLICY_PERIOD` by vendor number and policy number, filtered
     on non-expired cancel/completed dates.
6. Outcome: `Boolean hasAccess`, returned to the caller (typically an MVC controller/action in the
   Legal front end) to permit or deny display of claim/policy detail.

## Process flow

```mermaid
flowchart TD
	Start([IsPolicyValidForUser invoked]) --> Secure{SecurePolicyCode = SAIF and not authorized for SAIFpolicyInfo?}
	Secure -->|Yes| Deny1([Access denied])
	Secure -->|No| Valid{Policy IsValid and PolicyNum <> 0?}
	Valid -->|No| Deny2([Access denied])
	Valid -->|Yes| Branch{UserType?}
	Branch -->|SaifEmployee/MCO/MedProv/Bookkeeper| Grant1([Access granted])
	Branch -->|Agent| AgentCheck{Agent/agency number match?}
	AgentCheck -->|Yes| Grant2([Access granted])
	AgentCheck -->|No| Deny3([Access denied])
	Branch -->|PolicyHolder| ParentCheck{Own policy or parent affiliation match?}
	ParentCheck -->|Yes| Grant3([Access granted])
	ParentCheck -->|No| Deny4([Access denied])
	Branch -->|Group| GroupCheck{IsInGroup returns positive count?}
	GroupCheck -->|Yes| Grant4([Access granted])
	GroupCheck -->|No| Deny5([Access denied])
	Branch -->|LossControl| LCCheck{Assigned LC consultant matches user?}
	LCCheck -->|Yes| Grant5([Access granted])
	LCCheck -->|No| Deny6([Access denied])
	Branch -->|Auditor| AuditCheck{Non-expired audit record for vendor/policy?}
	AuditCheck -->|Yes| Grant6([Access granted])
	AuditCheck -->|No| Deny7([Access denied])
```

## Failure and edge-case behavior
- SAIF secure-policy check fails: access denied regardless of user type ([BR-VP-002](../business-rules.md#br-vp-002-secure-policy-ad-resource-gate)).
- Policy invalid or `PolicyNum = 0`: access denied ([BR-VP-003](../business-rules.md#br-vp-003-policy-validity-and-non-zero-policy-number-required-for-access)).
- No loss-control team assignment exists for the policy: access denied for `LossControl` users.

## Related documentation
- [Operations and processes](../operations-processes.md)
- [Business rules](../business-rules.md)
- [SQL catalog](../sql/index.md)
- [Database tables](../database-tables.md)
- [Security and authorization](../security-authorization.md)

> **Note:** Statements marked with `*` were inferred from code structure, naming
> conventions, or contextual evidence where direct confirmation was not available
> in source artifacts. Statements marked with `**` could not be confirmed; treat
> as unknown until verified.

## Sources
- `SAIF.Business.View.Policy\clsPolicySecurity.vb`
